﻿#Region "Import"

Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.Windows.Forms

#End Region

#Region "GlassPanel Class"

''' <summary>
''' Glass Panel Classs
''' </summary>
''' <remarks>Version 1.0.0</remarks>
<ToolboxItem(True), ToolboxBitmap(GetType(GlassPanel), "GlassPanel.GlassPanel.bmp"), ToolboxItemFilter("System.Windows.Forms"), Description("Display the Panel in a Glass Style.")> _
<DefaultEvent("Click"), DefaultProperty("Text")> _
Public Class GlassPanel
    Inherits System.Windows.Forms.Panel
#Region "Generic component"
    ''' <summary>
    ''' Initialize Components for GlassPanel
    ''' </summary>
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.SuspendLayout()
        '
        'GlassStylePanel
        '
        Me.ClientSize = New System.Drawing.Size(200, 100)
        Me.BorderStyle = Windows.Forms.BorderStyle.None
        Me.Name = "GlassPanel"
        Me.Text = "GlassPanel"
        Me.ResumeLayout(False)

    End Sub
    ''' <summary>
    ''' Constructor for GlassPanel
    ''' </summary>
    Sub New()
        MyBase.New()
        InitializeComponent()
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        SetStyle(ControlStyles.ResizeRedraw, True)
        SetStyle(ControlStyles.Opaque, False)
        SetStyle(ControlStyles.EnableNotifyMessage, True)
        SetStyle(ControlStyles.SupportsTransparentBackColor, True)
        BackColor = Color.Transparent
    End Sub
    ''' <summary>
    ''' Paint BackgroundSurface and Border for GlassPanel
    ''' </summary>
    ''' <param name="sender">ByVal sender As Object</param>
    ''' <param name="e">e As System.Windows.Forms.PaintEventArgs</param>
    Private Sub Panel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        PaintBackgoundSurface(Me, e)
        PaintBorder(Me, e)
    End Sub
    ''' <summary>
    ''' WndProc for GlassPanel
    ''' </summary>
    ''' <param name="m">ByRef m As System.Windows.Forms.Message</param>
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        MyBase.WndProc(m)
    End Sub

#End Region

#Region "Enumerations"

    Public Enum iBorderStyle
        None
        Rounded
    End Enum

    <Flags()> _
    Public Enum Corner
        None = 0
        TopLeft = 1
        TopRight = 2
        BottomLeft = 4
        BottomRight = 8
        All = TopLeft Or TopRight Or BottomLeft Or BottomRight
        AllTop = TopLeft Or TopRight
        AllLeft = TopLeft Or BottomLeft
        AllRight = TopRight Or BottomRight
        AllBottom = BottomLeft Or BottomRight
    End Enum

#End Region

#Region "Properties"
    ''' <summary>
    ''' Get or Set Opacity of GlassPanel
    ''' </summary>
    Private iOpacity As Integer = 25
    <Category("Glass"), _
    Description("Sets the opacity of the glass (between 0 [transparent] and 255 [opaque])")> _
    Overloads Property Opacity() As Integer
        Get
            Return iOpacity
        End Get
        Set(ByVal value As Integer)
            If value > 255 Then value = 255
            If value < 0 Then value = 0
            iOpacity = value
            Invalidate()
        End Set
    End Property
    ''' <summary>
    ''' Get or Set Glass Color for GlassPanel
    ''' </summary>
    Private clGlassColor As Color = Color.Black
    <Category("Glass"), _
    Description("Defines the color of the glass. Among good choices (WhiteSmoke, AliceBlue, MistyRose, AntiqueWhite, Ivory, HoneyDew, Lavender")> _
    Property GlassColor() As Color
        Get
            Return clGlassColor
        End Get
        Set(ByVal value As Color)
            clGlassColor = value
            Invalidate()
        End Set
    End Property
    ''' <summary>
    ''' Get or Set Border Style for GlassPanel
    ''' </summary>
    Private _BorderStyle As iBorderStyle = iBorderStyle.None
    Public Overloads Property BorderStyle() As iBorderStyle
        Get
            Return _BorderStyle
        End Get
        Set(ByVal value As iBorderStyle)
            _BorderStyle = value
            Me.Invalidate()
        End Set
    End Property

#End Region

#Region "Private Properties"
    ''' <summary>
    ''' Get Effective Bounds Of GlassPanel
    ''' </summary>
    ''' <returns>Returns Value As RectangleF</returns>
    <Browsable(False)> _
    ReadOnly Property EffectiveBounds() As RectangleF
        Get
            Return New RectangleF(ClientRectangle.X + 1, ClientRectangle.Y + 1, ClientRectangle.Width - 2, ClientRectangle.Height - 2)
        End Get
    End Property
    ''' <summary>
    ''' Get RoundedSurface Of GlassPanel
    ''' </summary>
    <Browsable(False)> _
    ReadOnly Property RoundSurface() As GraphicsPath
        Get
            Return RoundCorners(EffectiveBounds, Radius)
        End Get
    End Property
    ''' <summary>
    ''' Get Rounded Surface Inner of GlassPanel
    ''' </summary>
    <Browsable(False)> _
    ReadOnly Property RoundSurfaceInner() As GraphicsPath
        Get
            Dim rect As RectangleF = EffectiveBounds
            rect.Inflate(-1, -1)
            Return RoundCorners(rect, Radius)
        End Get
    End Property
    ''' <summary>
    ''' Get InnerRefion of GlassPanel
    ''' </summary>
    <Browsable(False)> _
    ReadOnly Property InnerRegion() As Region
        Get
            Dim rgInnerRegion As New Region(RoundSurface)
            Return rgInnerRegion
        End Get
    End Property
    ''' <summary>
    ''' Get Outer Region of GlassPanel
    ''' </summary>
    <Browsable(False)> _
    ReadOnly Property OuterRegion() As Region
        Get
            Dim rgOuterRegion As New Region(RoundSurface)
            rgOuterRegion.Xor(ClientRectangle)
            Return rgOuterRegion
        End Get
    End Property
    ''' <summary>
    ''' Get or Set Corner Radius Of GlassPanel
    ''' </summary>
    Private snRadius As Single = 5
    <Browsable(True)> _
    Property Radius() As Single
        Get
            Return snRadius
        End Get
        Set(ByVal value As Single)
            If value > 0 Then
                snRadius = value
            Else
                snRadius = 1
            End If
        End Set
    End Property

#End Region

#Region "Private Methods"
    ''' <summary>
    ''' Paint Backround Surface Of GlassPanel
    ''' </summary>
    Private Sub PaintBackgoundSurface(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        With e.Graphics
            .SmoothingMode = SmoothingMode.HighQuality
            .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
            .CompositingQuality = CompositingQuality.HighQuality
        End With
        Dim _GlassBrush As New SolidBrush(Color.FromArgb(CheckOpacity(Opacity), GlassColor.R, GlassColor.G, GlassColor.B))
        e.Graphics.FillPath(_GlassBrush, RoundSurface)
        PaintHorizontalSurface(sender, e)
        PaintGlowSurface(sender, e)
        PaintReflectiveBands(sender, e)
        PaintLightSource(sender, e)
    End Sub
    ''' <summary>
    ''' Paint ReflectiveBands for GlassPanel
    ''' </summary>
    Private Sub PaintReflectiveBands(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim _GlassReflectBrush As New SolidBrush(Color.FromArgb(CheckOpacity(Opacity * 0.5), GlassColor.R, GlassColor.G, GlassColor.B))
        Dim BandGraphicsPath1 As GraphicsPath = CreateReflectiveBand(0.1!, 0.5!, 0.15!)
        Dim BandGraphicsPath2 As GraphicsPath = CreateReflectiveBand(0.4!, 0.8!, 0.1!)
        e.Graphics.FillPath(_GlassReflectBrush, BandGraphicsPath1)
        e.Graphics.FillPath(_GlassReflectBrush, BandGraphicsPath2)
    End Sub
    ''' <summary>
    ''' Paint HorizontalSurface for GlassPanel
    ''' </summary>
    Private Sub PaintHorizontalSurface(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim _GlassDarkBrush As New SolidBrush(Color.FromArgb(Opacity * 2.5, DeductMinZero(GlassColor.R, 50), DeductMinZero(GlassColor.G, 50), DeductMinZero(GlassColor.B, 50)))
        e.Graphics.ExcludeClip(New Rectangle(EffectiveBounds.Left, EffectiveBounds.Top, EffectiveBounds.Width, EffectiveBounds.Height * 0.66!))
        e.Graphics.FillPath(_GlassDarkBrush, RoundSurface)
        e.Graphics.ResetClip()
    End Sub
    ''' <summary>
    ''' Paint Glow Surface for GlassPanel
    ''' </summary>
    Private Sub PaintGlowSurface(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim _GlassDarkLinearBrush As New LinearGradientBrush( _
            ClientRectangle, _
            Color.FromArgb(0, DeductMinZero(GlassColor.R, 50), DeductMinZero(GlassColor.G, 50), DeductMinZero(GlassColor.B, 50)), _
            Color.FromArgb(CheckOpacity(Opacity * 2.5), GlassColor.R, GlassColor.G, GlassColor.B), _
            LinearGradientMode.Vertical)
        e.Graphics.FillPath(_GlassDarkLinearBrush, RoundSurfaceInner)
    End Sub
    ''' <summary>
    ''' CreateReflective Bands for GlassPanel
    ''' </summary>
    Private Function CreateReflectiveBand(ByVal LeftFactor As Single, ByVal RightFactor As Single, ByVal SizeFactor As Single) As GraphicsPath
        Dim BandGraphicsPath As New GraphicsPath
        With BandGraphicsPath
            .StartFigure()
            .AddLine(2 + (EffectiveBounds.Width * LeftFactor), 2, 2 + (EffectiveBounds.Width * LeftFactor) + (EffectiveBounds.Width * SizeFactor), 2)
            .AddLine((2 + (EffectiveBounds.Width * LeftFactor)) + (EffectiveBounds.Width * SizeFactor), 2, (2 + (EffectiveBounds.Width * RightFactor)) + (EffectiveBounds.Width * SizeFactor), EffectiveBounds.Top + EffectiveBounds.Height)
            .AddLine((2 + (EffectiveBounds.Width * RightFactor) + (EffectiveBounds.Width * SizeFactor)), 2 + EffectiveBounds.Height, EffectiveBounds.Left + (EffectiveBounds.Width * RightFactor), EffectiveBounds.Top + EffectiveBounds.Height)
            .AddLine(2 + (EffectiveBounds.Width * RightFactor), 2 + EffectiveBounds.Height, 2 + (EffectiveBounds.Width * LeftFactor), 2)
            .CloseFigure()
        End With
        Return BandGraphicsPath
    End Function
    ''' <summary>
    ''' Paint Light Source for GlassPanel
    ''' </summary>
    Private Sub PaintLightSource(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim _RectangleLight As RectangleF = GetLightBounds(0.75)
        Dim _LightGraphicsPath As New GraphicsPath
        _LightGraphicsPath.StartFigure()
        _LightGraphicsPath.AddEllipse(_RectangleLight)
        Dim brLight As New PathGradientBrush(_LightGraphicsPath)
        brLight.CenterColor = Color.FromArgb(CheckOpacity(Opacity * 3), 255, 255, 255)
        brLight.SurroundColors = New Color() {Color.FromArgb(0, 255, 255, 255)}
        e.Graphics.ExcludeClip(OuterRegion)
        e.Graphics.FillEllipse(brLight, _RectangleLight)
        e.Graphics.ResetClip()
    End Sub
    ''' <summary>
    ''' Returns Light Band for GlassPanel
    ''' </summary>
    Private Function GetLightBounds(ByVal Size As Single) As RectangleF
        Return New RectangleF(2 - ((EffectiveBounds.Height * Size) \ 2), 2 - ((EffectiveBounds.Height * Size) \ 2), EffectiveBounds.Height * Size, EffectiveBounds.Height * Size)
    End Function
    ''' <summary>
    ''' Paint Border of GlassPanel
    ''' </summary>
    Private Sub PaintBorder(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        If _BorderStyle = iBorderStyle.Rounded Then
            e.Graphics.DrawPath(New Pen(Color.FromArgb(200, 255, 255, 255), 0.5!), RoundSurface)
            e.Graphics.DrawPath(New Pen(Color.FromArgb(255, 0, 0, 0), 0.5!), RoundSurfaceInner)
        End If
    End Sub

#End Region

#Region "Public Functions"

    Public Function CheckOpacity(ByVal Value As Integer) As Integer
        If Value > 255 Then
            Return 255
        ElseIf Value < 0 Then
            Return 0
        Else
            Return Value
        End If
    End Function

    Public Function DeductMinZero(ByVal Value As Integer, ByVal Deduction As Integer) As Integer
        If Value - Deduction < 0 Then
            Return 0
        Else
            Return Value - Deduction
        End If
    End Function

    Public Function RoundCorners(ByVal Rectangle As RectangleF, Optional ByVal Radius As Integer = 5, Optional ByVal Corners As Corner = Corner.All) As Drawing2D.GraphicsPath
        Dim p As New Drawing2D.GraphicsPath
        Dim x As Single = Rectangle.X
        Dim y As Single = Rectangle.Y
        Dim w As Single = Rectangle.Width
        Dim h As Single = Rectangle.Height
        Dim r As Integer = Radius
        p.StartFigure()
        If CBool(Corners And Corner.TopLeft) Then
            p.AddArc(New RectangleF(x, y, 2 * r, 2 * r), 180, 90)
        Else
            p.AddLine(New PointF(x, y + r), New PointF(x, y))
            p.AddLine(New PointF(x, y), New PointF(x + r, y))
        End If
        p.AddLine(New PointF(x + r, y), New PointF(x + w - r, y))
        If CBool(Corners And Corner.TopRight) Then
            p.AddArc(New RectangleF(x + w - 2 * r, y, 2 * r, 2 * r), 270, 90)
        Else
            p.AddLine(New PointF(x + w - r, y), New PointF(x + w, y))
            p.AddLine(New PointF(x + w, y), New PointF(x + w, y + r))
        End If
        p.AddLine(New PointF(x + w, y + r), New PointF(x + w, y + h - r))
        If CBool(Corners And Corner.BottomRight) Then
            p.AddArc(New RectangleF(x + w - 2 * r, y + h - 2 * r, 2 * r, 2 * r), 0, 90)
        Else
            p.AddLine(New PointF(x + w, y + h - r), New PointF(x + w, y + h))
            p.AddLine(New PointF(x + w, y + h), New PointF(x + w - r, y + h))
        End If
        p.AddLine(New PointF(x + w - r, y + h), New PointF(x + r, y + h))
        If CBool(Corners And Corner.BottomLeft) Then
            p.AddArc(New RectangleF(x, y + h - 2 * r, 2 * r, 2 * r), 90, 90)
        Else
            p.AddLine(New PointF(x + r, y + h), New PointF(x, y + h))
            p.AddLine(New PointF(x, y + h), New PointF(x, y + h - r))
        End If
        p.AddLine(New PointF(x, y + h - r), New PointF(x, y + r))
        p.CloseFigure()
        Return p
    End Function

#End Region

End Class

#End Region